package model;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;

public class Element implements Comparable<Element> {
	private String name;
	private HashMap<Element, Element> combinations;
	private Set<Element> origins;

	public Element(String name) {
		this.name = name;
		combinations = new HashMap<Element, Element>();
		origins = new HashSet<Element>();
	}

	public void addCombination(Element element, Element result) {
		combinations.put(element, result);
	}

	public Element combine(Element element) {
		return combinations.get(element);
	}

	public String getName() {
		return name;
	}

	public void addOrigin(Element element) {
		origins.add(element);
	}

	public boolean isBasic() {
		if (origins.isEmpty()) {
			return true;
		}
		return false;
	}

	public boolean isTerminal() {
		if (combinations.isEmpty()) {
			return true;
		}
		return false;
	}

	public Set<Element> getOrigins() {
		if (origins.isEmpty()) {
			return null;
		}
		Set<Element> or = new TreeSet<Element>();
		getOrigins(or);
		Set<Element> basic = new TreeSet<Element>();
		for (Element e : or) {
			if (e.isBasic()) {
				basic.add(e);
			}
		}
		return basic;
	}

	private void getOrigins(Set<Element> or) {
		for (Element e : origins) {
			if (!or.contains(e)) {
				or.add(e);
				e.getOrigins(or);
			}
		}

	}

	public Set<Element> getAllCombinations() {
		if (combinations.isEmpty()) {
			return new TreeSet<Element>();
		}
		Set<Element> comb = new TreeSet<Element>();
		getAllCombinations(comb);
		return comb;
	}

	private void getAllCombinations(Set<Element> comb) {
		for (Element e : combinations.values()) {
			if (!comb.contains(e)) {
				comb.add(e);
				if (!e.isTerminal()) {
					e.getAllCombinations(comb);
				}
			}
		}

	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Element other = (Element) obj;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}

	public String toString() {
		return name;
	}

	@Override
	public int compareTo(Element e) {

		return this.name.compareTo(e.getName());
	}

}